package io.gitee.vexlife.snake;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;

import javax.swing.JCheckBoxMenuItem;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

import io.gitee.vexlife.snake.basic.Food;
import io.gitee.vexlife.snake.basic.FoodShape;
import io.gitee.vexlife.snake.basic.Node;
import io.gitee.vexlife.snake.basic.Snake;
import io.gitee.vexlife.snake.ui.MainFrame;
import io.gitee.vexlife.snake.ui.SettingsDialog;

public class GameController {
	private static Snake snake;
	private static Food food;
	private boolean over;
	private int width, height, gameInterval, initialSnakeLength;
	private ArrayList<IAgent> agents;
	private IAgent selectedAgent;
	private MainFrame mainframe;
	private boolean activatedFlag;
	public JDialog settingsCollector;
	public static Color color_Snake, color_Food, color_Background;
	public static int UNIT_SIZE, SNAKE_STROKE, FOOD_STROKE;
	public static FoodShape shape_Food;

	public GameController(JDialog settingsCollector, int width, int height, int gameInterval, int initialSnakeLength,
			int UNIT_SIZE, int SNAKE_STROKE, int FOOD_STROKE, Color color_Snake, Color color_Food,
			Color color_Background, FoodShape shape_Food) {
		if (initialSnakeLength > width)
			throw new IllegalArgumentException("蛇长不应超过宽度！");
		this.width = width;
		this.height = height;
		this.gameInterval = gameInterval;
		this.over = false;
		this.activatedFlag = true;
		this.agents = new ArrayList<IAgent>();
		this.initialSnakeLength = initialSnakeLength;
		this.color_Snake = color_Snake;
		this.color_Food = color_Food;
		this.color_Background = color_Background;
		this.UNIT_SIZE = UNIT_SIZE;
		this.SNAKE_STROKE = SNAKE_STROKE;
		this.FOOD_STROKE = FOOD_STROKE;
		this.shape_Food = shape_Food;
		this.settingsCollector = settingsCollector == null ? new SettingsDialog(this) : settingsCollector;
		this.mainframe = new MainFrame(this);
	}

	public GameController(int width, int height, int gameInterval, int initialSnakeLength) {
		this(width, height, gameInterval, initialSnakeLength, 10, 8, 8);
	}

	public GameController(int width, int height, int gameInterval, int initialSnakeLength, IAgent[] agents) {
		this(width, height, gameInterval, initialSnakeLength, 10, 8, 8, agents);
	}

	public GameController(int width, int height, int gameInterval, int initialSnakeLength, IAgent agent) {
		this(width, height, gameInterval, initialSnakeLength, 10, 8, 8, agent);
	}

	public GameController(int width, int height, int gameInterval, int initialSnakeLength, int UNIT_SIZE,
			int SNAKE_STROKE, int FOOD_STROKE, IAgent[] agents) {
		this(width, height, gameInterval, initialSnakeLength, UNIT_SIZE, SNAKE_STROKE, FOOD_STROKE, Color.BLACK,
				Color.RED, Color.WHITE, FoodShape.SQUARE, agents);
	}

	public GameController(int width, int height, int gameInterval, int initialSnakeLength, int UNIT_SIZE,
			int SNAKE_STROKE, int FOOD_STROKE, IAgent agent) {
		this(width, height, gameInterval, initialSnakeLength, UNIT_SIZE, SNAKE_STROKE, FOOD_STROKE, Color.BLACK,
				Color.RED, Color.WHITE, FoodShape.SQUARE, agent);
	}

	public GameController(int width, int height, int gameInterval, int initialSnakeLength, int UNIT_SIZE,
			int SNAKE_STROKE, int FOOD_STROKE) {
		this(width, height, gameInterval, initialSnakeLength, UNIT_SIZE, SNAKE_STROKE, FOOD_STROKE, Color.BLACK,
				Color.RED, Color.WHITE, FoodShape.SQUARE);
	}

	public GameController(int width, int height, int gameInterval, int initialSnakeLength, Color color_Snake,
			Color color_Food, Color color_Background, FoodShape shape_Food, IAgent agents[]) {
		this(width, height, gameInterval, initialSnakeLength, 10, 8, 8, color_Snake, color_Food, color_Background,
				shape_Food, agents);
	}

	public GameController(int width, int height, int gameInterval, int initialSnakeLength, Color color_Snake,
			Color color_Food, Color color_Background, FoodShape shape_Food, IAgent agent) {
		this(width, height, gameInterval, initialSnakeLength, 10, 8, 8, color_Snake, color_Food, color_Background,
				shape_Food, agent);
	}

	public GameController(int width, int height, int gameInterval, int initialSnakeLength, Color color_Snake,
			Color color_Food, Color color_Background, FoodShape shape_Food) {
		this(width, height, gameInterval, initialSnakeLength, 10, 8, 8, color_Snake, color_Food, color_Background,
				shape_Food);
	}

	public GameController(int width, int height, int gameInterval, int initialSnakeLength, int UNIT_SIZE,
			int SNAKE_STROKE, int FOOD_STROKE, Color color_Snake, Color color_Food, Color color_Background,
			FoodShape shape_Food, IAgent[] agents) {
		this(width, height, gameInterval, initialSnakeLength, UNIT_SIZE, SNAKE_STROKE, FOOD_STROKE, color_Snake,
				color_Food, color_Background, shape_Food);
		this.registerAgent(agents);
	}

	public GameController(int width, int height, int gameInterval, int initialSnakeLength, int UNIT_SIZE,
			int SNAKE_STROKE, int FOOD_STROKE, Color color_Snake, Color color_Food, Color color_Background,
			FoodShape shape_Food, IAgent agent) {
		this(width, height, gameInterval, initialSnakeLength, UNIT_SIZE, SNAKE_STROKE, FOOD_STROKE, color_Snake,
				color_Food, color_Background, shape_Food, new IAgent[] { agent });
	}

	public GameController(int width, int height, int gameInterval, int initialSnakeLength, int UNIT_SIZE,
			int SNAKE_STROKE, int FOOD_STROKE, Color color_Snake, Color color_Food, Color color_Background,
			FoodShape shape_Food) {
		this(null, width, height, gameInterval, initialSnakeLength, UNIT_SIZE, SNAKE_STROKE, FOOD_STROKE, color_Snake,
				color_Food, color_Background, shape_Food);
	}

	public GameController(JDialog settingsChooser, int width, int height, int gameInterval, int initialSnakeLength,
			int UNIT_SIZE, int SNAKE_STROKE, int FOOD_STROKE, Color color_Snake, Color color_Food,
			Color color_Background, FoodShape shape_Food, IAgent[] agents) {
		this(settingsChooser, width, height, gameInterval, initialSnakeLength, UNIT_SIZE, SNAKE_STROKE, FOOD_STROKE,
				color_Snake, color_Food, color_Background, shape_Food);
		this.registerAgent(agents);
	}

	public GameController(JDialog settingsChooser, int width, int height, int gameInterval, int initialSnakeLength,
			int UNIT_SIZE, int SNAKE_STROKE, int FOOD_STROKE, Color color_Snake, Color color_Food,
			Color color_Background, FoodShape shape_Food, IAgent agent) {
		this(settingsChooser, width, height, gameInterval, initialSnakeLength, UNIT_SIZE, SNAKE_STROKE, FOOD_STROKE,
				color_Snake, color_Food, color_Background, shape_Food, new IAgent[] { agent });
	}

	public Snake getSnake() {
		return this.snake;
	}

	public Food getFood() {
		return this.food;
	}

	public int getWidth() {
		return this.width;
	}

	public int getHeight() {
		return this.height;
	}

	public void gameOver() {
		this.setOver(true);
		if (JOptionPane.showOptionDialog(this.mainframe, "游戏结束！是否重开？", "提示", JOptionPane.YES_NO_OPTION,
				JOptionPane.PLAIN_MESSAGE, null, null, JOptionPane.YES_OPTION) == JOptionPane.YES_OPTION)
			this.startGame();
	}

	public void startGame() {
		LinkedList<Node> snake_pos = new LinkedList<Node>();
		for (int i = 0; i < this.initialSnakeLength; i++) {
			snake_pos.add(new Node(i, height / 2));
		}
		this.snake = new Snake(snake_pos);
		this.food = new Food();
		food.genFood(this);
		this.setOver(true);
		try {
			Thread.sleep(this.gameInterval);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.continueGame();
		this.mainframe.Show();
	}

	public void continueGame() {
		this.setOver(false);
		new Thread(new GameHost(this)).start();
	}

	public JFrame getMainFrame() {
		return this.mainframe;
	}

	public int getGameInterval() {
		return gameInterval;
	}

	public void setGameInterval(int gameInterval) {
		this.gameInterval = gameInterval;
	}

	public boolean isEmpty(Node node) {
		return node.getX() >= 0 && node.getY() >= 0 && node.getX() < this.width && node.getY() < this.height
				&& !this.snake.getNodes().contains(node);
	}

	public boolean isOver() {
		return this.over;
	}

	public void setOver(boolean over) {
		this.over = over;
	}

	public boolean isActivated() {
		return this.activatedFlag;
	}

	public void setActivatedFlag(boolean activatedFlag) {
		this.activatedFlag = activatedFlag;
	}

	public void registerAgent(IAgent[] agents) {
		this.agents.addAll(Arrays.asList(agents));
		this.mainframe.updateAgents();
	}

	public void registerAgent(IAgent agent) {
		this.registerAgent(new IAgent[] { agent });
	}

	public ArrayList<IAgent> getAgents() {
		return this.agents;
	}

	public IAgent getSelectedAgent() {
		return selectedAgent;
	}

	public void selectAgent(Integer index) {
		JCheckBoxMenuItem item = (JCheckBoxMenuItem) this.mainframe.getJMenuBar().getMenu(1)
				.getMenuComponent(this.selectedAgent == null ? this.agents.size() + 1 : this.agents.indexOf(selectedAgent));
		if (item == null) {
			this.mainframe.updateAgents();
			return;
		}
		item.setSelected(false);
		item = (JCheckBoxMenuItem) this.mainframe.getJMenuBar().getMenu(1)
				.getMenuComponent(index == -1 ? this.agents.size() + 1 : index);
		item.setSelected(true);
		if (index == -1) {
			this.selectedAgent = null;
		} else {
			this.getAgents().get(index).initAgent(this);
			this.selectedAgent = this.getAgents().get(index);
		}
	}

	public Node[] getEmptyPositions() {
		Node[] emptyPositions = new Node[this.width * this.height - this.snake.getLength()];
		int pointer = 0;
		for (int i = 0; i < this.width; i++) {
			for (int j = 0; j < this.height; j++) {
				Node point = new Node(i, j);
				if (this.snake.getNodes().contains(point))
					continue;
				emptyPositions[pointer] = point;
				pointer++;
			}
		}
		return emptyPositions;
	}

	public int getInitialSnakeLength() {
		return initialSnakeLength;
	}

	public void setInitialSnakeLength(int initialSnakeLength) {
		this.initialSnakeLength = initialSnakeLength;
	}
}
